﻿#pragma once
#include <cocos2d.h>
#include <vector>
#include <map>
#include <string>

using namespace std;

USING_NS_CC;

#define POOL_DEBUG 0

template <class T>
class PoolObject : public CCObject
{
public:
	PoolObject(void);
	~PoolObject(void);

	static PoolObject<T>* _instance;
	static PoolObject<T>* sharedPoolObject();


	//map<string, vector<T*>*> _mapBulletReady;
	CC_SYNTHESIZE_RETAIN(CCDictionary*, _mapBulletReady, BulletReadyMap);
	//vector<T*> _listObject;
	CC_SYNTHESIZE_RETAIN(CCArray*, _listObject, Objects);
	T* getObjectWithId(string id);
	void clearPool();
};

template <class T>
void PoolObject<T>::clearPool()
{
	delete _instance;
	_instance = NULL;
}

template <class T>
T* PoolObject<T>::getObjectWithId(string id)
{
	// Tìm kiếm trong map nếu không tìm ra
	if (_mapBulletReady->objectForKey(id) == NULL)
	{
		_mapBulletReady->setObject(CCArray::create(), id);
	}

	CCArray* listReady = dynamic_cast<CCArray*>(_mapBulletReady->objectForKey(id));
	if (listReady->count() != 0)
	{
		if (POOL_DEBUG)
			CCLog("PoolObject: reuse object %s", id.c_str());
		T* result = dynamic_cast<T*>(listReady->objectAtIndex(0));
		listReady->removeObjectAtIndex(0);
		result->reset();
		return result;
	}
	for (int i = 0; i < _listObject->count(); i++)
	{
		T* it = dynamic_cast<T*>(_listObject->objectAtIndex(i));
		if (it->retainCount() == 1) // no one use it
		{
			string toId = it->getId()->getCString();
			CCArray* readyList = dynamic_cast<CCArray*>(_mapBulletReady->objectForKey(toId));
			if (!readyList->containsObject(it))
				readyList->addObject(it);
		}
	}
	if (listReady->count() == 0)
	{
		if (POOL_DEBUG)
			CCLOG("PoolObject: ADD NEW object %s", id.c_str());
		T* it = T::create();
		_listObject->addObject(it);
		return it;
	}
	if (POOL_DEBUG)
		CCLog("PoolObject: reuse object %s", id.c_str());
	T* result = dynamic_cast<T*>(listReady->objectAtIndex(0));
	listReady->removeObjectAtIndex(0);
	result->reset();
	return result;
}

template <class T>
PoolObject<T>* PoolObject<T>::sharedPoolObject()
{
	if (_instance == NULL)
		_instance = new	PoolObject<T>();
	return _instance;
}

template <class T>
PoolObject<T>::~PoolObject( void )
{
	CC_SAFE_RELEASE(_mapBulletReady);
	CC_SAFE_RELEASE(_listObject);
}

template <class T>
PoolObject<T>::PoolObject( void )
{
	_mapBulletReady = NULL;
	_listObject = NULL;
	setBulletReadyMap(CCDictionary::create());
	setObjects(CCArray::create());
}

template <class T>
	PoolObject<T>* PoolObject<T>::_instance = NULL;

